﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Basic.Model;
using Common.Library;
using Common.Model;
using Container.Library;
using Redis.Library;
using Serialize.Library;

/*
* 命名空间: Basic.Logic
*
* 功 能： 接口访问监控日志逻辑类
*
* 类 名： ApiMonitorLogServiceImpl
*
* Version   变更日期            负责人     变更内容
* ─────────────────────────────────────────────────
* V1.0.1    2020/03/17 14:34:43 李聪     创建
*
* Copyright (c) 2020 Lir Corporation. All rights reserved.
*/

namespace Basic.Logic
{
    /// <summary>
    /// 接口访问监控日志逻辑类
    /// </summary>
    public class ApiMonitorLogServiceImpl : OperationLogicImpl, IApiMonitorLogService
    {

        #region 接口访问监控日志明细操作

        /// <summary>
        /// 根据访问监控日志条件分页获取列表 关键字【控制器名称】【方法名】  开始时间
        /// </summary>
        /// <param name="inputInfo"></param>
        /// <returns></returns>
        public ResultJsonInfo<List<ApiMonitorLogResponse>> LoadApiMonitorLogList(ParametersInfo<ApiMonitorLogQueryRequest> inputInfo)
        {

            var resultInfo = new ResultJsonInfo<List<ApiMonitorLogResponse>>();

            //异常日志，直接操作Redis数据库
            ApiMonitorLogServiceRedis.GetAllApiMonitorLog((result) =>
            {
                if (inputInfo.parameters.sKeyWords.IsNotNullOrEmpty())
                {
                    result = result.Where(p => p.action_name.Contains(inputInfo.parameters.sKeyWords) || p.controller_name.Contains(inputInfo.parameters.sKeyWords)).ToList();
                }
                if (inputInfo.parameters.exception_time != null)
                {
                    result = result.Where(p => p.start_time >= inputInfo.parameters.exception_time).ToList();
                }
                var listInfo = result.OrderByDescending(p => p.start_time)
                                    .Skip((inputInfo.page - 1) * inputInfo.limit).Take(inputInfo.limit)
                                    .ToList();

                if (listInfo.Count > 0)
                {
                    resultInfo.Code = ActionCodes.Success;
                    resultInfo.Data = listInfo.MapToList<ApiMonitorLogResponse>();
                    resultInfo.Count = result.Count;
                }
                else
                {
                    resultInfo.Msg = "无对应信息！";
                }
            },
            () =>
            {
                resultInfo.Msg = "无对应信息！";
            });
            return resultInfo;
        }

        /// <summary>
        /// 批量删除访问监控日志
        /// </summary>
        /// <returns></returns>
        public ResultJsonInfo<int> Remove(ApiMonitorLogRequest request)
        {
            var resultInfo = new ResultJsonInfo<int>();

            ApiMonitorLogServiceRedis.GetAllApiMonitorLog((result) =>
            {
                var time = request.endTime.AddDays(1);

                var listInfo = result.Where(p => p.start_time >= request.startTime && p.start_time < time).Select(p => p.id).ToList();
                if (listInfo.Count > 0)
                {
                    ApiMonitorLogServiceRedis.RemoveApiMonitorLog(listInfo);
                    resultInfo.Code = ActionCodes.Success;
                    resultInfo.Msg = "操作成功！";
                    AddOperationLog(OperationLogType.RemoveOperation, BusinessTitleType.ApiLogManage, $"批量删除访问监控日志:{JsonHelper.ToJson(request)}");
                }
                else
                {
                    resultInfo.Msg = "操作失败！";
                }
            },
            () =>
            {
                resultInfo.Msg = "无对应信息！";
            });
            return resultInfo;
        }

        #endregion

        #region 接口访问监控日志统计操作

        /// <summary>
        /// 统计接口请求信息
        /// </summary>
        public void StatisticsInterfaceRequest(int seconds)
        {
            //请求日志，直接操作Redis数据库
            ApiMonitorLogServiceRedis.GetAllApiMonitorLog((result) =>
            {
                DateTime timeNow = DateTime.Now;

                if (result.Count > 0)
                {

                    var listInfo = result.Where(p => p.start_time >= timeNow.AddSeconds(-seconds) && p.start_time < timeNow).ToList();

                    #region 访问总数量
                    //按接口统计
                    var groupList = listInfo.GroupBy(p => new { p.start_time }).
                             Select(a => new ApiMonitorLogGroup
                             {
                                 id = GuidHelper.GetGuid(),
                                 statistics_time = a.Key.start_time,
                                 frequency = a.Count()
                             }).ToList();
                    //插入接口统计信息
                    ApiMonitorLogServiceRedis.SaveGroup(groupList);
                    #endregion

                    #region 接口路由统计

                    //按接口路由统计
                    var groupPathList = listInfo.GroupBy(p => new { p.request_path, p.start_time }).
                             Select(a => new ApiMonitorLogPathGroup
                             {
                                 id = GuidHelper.GetGuid(),
                                 request_path = a.Key.request_path,
                                 statistics_time = a.Key.start_time,
                                 frequency = a.Count()
                             }).ToList();
                    //插入接口路由统计信息
                    ApiMonitorLogServiceRedis.SaveGroupPath(groupPathList);

                    #endregion

                    #region 按接口路由和Ip统计


                    var groupPathIpList = listInfo.GroupBy(p => new { p.request_path, p.request_ip, p.start_time }).
                           Select(a => new ApiMonitorLogPathIpGroup
                           {
                               id = GuidHelper.GetGuid(),
                               request_path = a.Key.request_path,
                               request_ip = a.Key.request_ip,
                               statistics_time = a.Key.start_time,
                               frequency = a.Count()
                           }).ToList();
                    //插入接口路由和Ip统计信息
                    ApiMonitorLogServiceRedis.SaveGroupPathIp(groupPathIpList);
                    #endregion

                    //已存在所有的名单信息【警告、黑名单】
                    var allNameList = ApiMonitorLogServiceRedis.GetAllNameList();
                    //黑名单
                    var noAccessNameList = allNameList.Where(p => p.name_type == (int)NameListType.NoAccess).ToList();

                    foreach (var item in groupPathIpList)
                    {
                        //进入警告名单
                        if (item.frequency >= BasicRedisInfo.WarningOnLine && item.frequency < BasicRedisInfo.NoAccessOnLine)
                        {
                            if (!allNameList.Exists(p => p.request_ip == item.request_ip))
                            {
                                ApiMonitorLogServiceRedis.SaveNameList(new ApiMonitorLogNameList()
                                {
                                    request_ip = item.request_ip,
                                    name_type = (int)NameListType.Warning
                                });
                            }
                        }

                        //黑名单
                        if (item.frequency >= BasicRedisInfo.NoAccessOnLine)
                        {
                            if (!noAccessNameList.Exists(p => p.request_ip == item.request_ip))
                            {
                                ApiMonitorLogServiceRedis.SaveNameList(new ApiMonitorLogNameList()
                                {
                                    request_ip = item.request_ip,
                                    name_type = (int)NameListType.NoAccess
                                });
                            }
                        }
                    }
                }
            });
        }

        /// <summary>
        /// 获取接口实时访问统计信息
        /// </summary>
        /// <param name="timed"></param>
        /// <returns></returns>
        public ResultJsonInfo<Echarts2DCoordinatesInfo> loadRequestInfo(DateTime timed)
        {
            var resultInfo = new ResultJsonInfo<Echarts2DCoordinatesInfo>();

            //设置22秒后退出循环
            for (int i = 0; i < 15; i++)
            {
                var result = ApiMonitorLogServiceRedis.GetAllApiMonitorLogGroup();
                if (result!=null&& result.Count>0)
                {
                    //延迟10秒返回数据
                    var latestGroup = result.Where(p => p.statistics_time >= timed.AddSeconds(10)).ToList();
                    if (latestGroup.Count>0)
                    {
                        var resultGroupInfo = result.Where(p => p.statistics_time >= timed.AddSeconds(-60)).OrderBy(p => p.statistics_time).ToList();

                        resultInfo.Data = new Echarts2DCoordinatesInfo()
                        {
                            xAxis = resultGroupInfo.Select(p => p.statistics_time.ToString("hh:mm:ss")).ToList(),
                            yAxis = resultGroupInfo.Select(p => p.frequency.ToString()).ToList()
                        };
                        resultInfo.Code = ActionCodes.Success;
                        resultInfo.Msg = "操作成功！";
                        break;
                    }
                }
                Thread.Sleep(1000);//等待一秒钟保持连接
            }

            if (resultInfo.Code != ActionCodes.Success)
            {
                var result = ApiMonitorLogServiceRedis.GetAllApiMonitorLogGroup();
                var resultGroupInfo = result.Where(p => p.statistics_time >= timed.AddSeconds(-60)).OrderBy(p => p.statistics_time).ToList();

                resultInfo.Data = new Echarts2DCoordinatesInfo()
                {
                    xAxis = resultGroupInfo.Select(p => p.statistics_time.ToString("hh:mm:ss")).ToList(),
                    yAxis = resultGroupInfo.Select(p => p.frequency.ToString()).ToList()
                };
                resultInfo.Code = ActionCodes.Success;
                resultInfo.Msg = "操作成功！";
            }
            return resultInfo;
        }


        /// <summary>
        /// 获取某个时间段内的接口实时访问统计信息
        /// </summary>
        /// <param name="beginTime"></param>
        /// <param name="endTime"></param>
        /// <returns></returns>
        public ResultJsonInfo<Echarts2DCoordinatesInfo> loadRequestInfoByTime(DateTime beginTime, DateTime endTime)
        {
            var resultInfo = new ResultJsonInfo<Echarts2DCoordinatesInfo>();

            var result = ApiMonitorLogServiceRedis.GetAllApiMonitorLogGroup();
            if (result != null && result.Count > 0)
            {
                var latestGroup = result.Where(p => p.statistics_time >= beginTime && p.statistics_time < endTime).ToList();
                if (latestGroup.Count > 0)
                {
                    resultInfo.Data = new Echarts2DCoordinatesInfo()
                    {
                        xAxis = latestGroup.Select(p => p.statistics_time.ToString("hh:mm:ss")).ToList(),
                        yAxis = latestGroup.Select(p => p.frequency.ToString()).ToList()
                    };
                    resultInfo.Code = ActionCodes.Success;
                    resultInfo.Msg = "操作成功！";
                }
            }
            return resultInfo;
        }
        #endregion
    }
}
